
#include <stdio.h>

#include "Snow.h"


Snow::Snow(int width, int height, Origin *heightfield) :
	w_width(width), w_height(height),
			num_flakes(1000), lsite(NULL), wind(NULL),frog(false) {
	reset();
	this->origin = heightfield;
}

Snow::~Snow() {
}

void Snow::reset() {
	init();

	spin.x = 0;
	spin.y = 0;
	anchor = spin;
	lastspin = spin;
	rscale = 0.0005f;

	if (wind) {
		delete wind;
		wind = NULL;
	}
	wind = new vector3f(0.00f, 0.0f, 0.00f);
	windc = 0.001f;
	veloc = 0.001f;
}

void Snow::increaseSnow(int n, bool spawn) {
	flake f;

	if (spawn) {
		for (int i = 0; i < n; i++) {
			f.reset();
			snow.push_back(f);
		}
	}

	else {
		for (int i = 0; i < n; i++) {
			f.init();
			snow.push_back(f);
		}
	}
}

void Snow::decreasSnow(int n) {
	while (!snow.empty() && n > 0) {
		snow.pop_back();
		n--;
	}
}



void Snow::setNum_flakes(int n)
{
	num_flakes=snow.size();
	if(n>num_flakes)
		increaseSnow(n-num_flakes,false);
	else if(n<num_flakes)
		decreasSnow(num_flakes-n);
}



void Snow::initialize(floatbuffer* zbuf) {
	snow.clear();
	increaseSnow(num_flakes, false);
	lsite = new SiteSet(zbuf);
	ground=new SiteSet(zbuf,true);
	delete zbuf;
}




void Snow::drawflakes() {
	launchSite* e;
	launchSite* g;
	list<flake>::iterator f;

	int x, y;

	glPointSize(3);

	glColor3f(1, 1, 1); //should use glmaterial instead


	glBegin(GL_POINTS);

	for (f = snow.begin(); f != snow.end(); f++) {
		f->nextPos(rscale, wind);

		x = (int) ((f->pos.x + 1.0) / 2.0 * (lsite->w));
		y = (int) ((f->pos.z + 1.0) / 2.0 * (lsite->h));
		if (x >= lsite->w)
			x -= 1;
		if (y >= lsite->h)
			y -= 1;

		e = &lsite->elements[x][y];
		g=&ground->elements[x][y];

		//test for groud
		if(f->pos.y<=g->accum){

				g->accumulate(f->size);

			f->reset();
		}

		//test the object.  -0.2 to add fly from side in
		else if ((f->pos.y <= e->accum)&& (f->pos.y > e->accum-0.2)){


				e->accumulate(f->size);

			f->reset();
		}
		else
			f->plot();
	}

	glEnd();
}


void Snow::drawaccumulatedsnow() {
	int x, y;
	launchSite* e;
	launchSite* g;
//	glLineWidth(4.0);
/*	if(texture)
	{
		GLfloat position[]={0.0,1.0,-1.0,0.0};
		GLfloat ambient[]={0.8,0.8,0.8};
		GLfloat diffuse[]={0.8,0.8,0.8};
		glLightfv(GL_LIGHT1,GL_AMBIENT,ambient);
		glLightfv(GL_LIGHT1,GL_DIFFUSE,diffuse);
		glLightfv(GL_LIGHT1,GL_SPECULAR,snowMaterial.specular);
		glLightfv(GL_LIGHT1,GL_POSITION,position);

		//glLightfv(GL_LIGHT0,GL_AMBIENT,snowMaterial.ambient);
			//	glLightfv(GL_LIGHT0,GL_DIFFUSE,snowMaterial.diffuse);
				//glLightfv(GL_LIGHT0,GL_SPECULAR,snowMaterial.specular);


		glEnable(GL_DEPTH_TEST);
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		glEnable(GL_LIGHT1);


        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, snowMaterial.ambient);
         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, snowMaterial.diffuse);
         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, snowMaterial.specular);
         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, snowMaterial.shininess);

	}
	else
	{*/
		glDisable(GL_LIGHTING);
		glDisable(GL_LIGHT0);



//	glBegin(GL_QUAD_STRIP);
	for (y = 0; y < lsite->h; y++) {
		for (x = 0; x < lsite->w; x++) {
			e = &(lsite->elements[x][y]);
			g=&(ground->elements[x][y]);
			if(e->hassnow)
			{
				e->plotbase();
				e->plotaccum();
			}
		if(g->hassnow)
			{
				g->plotbase();
				g->plotaccum();
			}
		}
	}
	glEnd();

}

void Snow::display(void) {
	char stringy[500];
if(frog) //enable frog
{
static	GLfloat angle = 0.0;

	GLfloat density = 0.3; //set the density to 0.3 which is acctually quite thick
	GLfloat fogColor[4] = {0.9, 0.9, 0.9, 1.0}; //set the for color to grey
	glEnable(GL_FOG);
	glFogi (GL_FOG_MODE, GL_EXP2); //set the fog mode to GL_EXP2
	glFogfv (GL_FOG_COLOR, fogColor); //set the fog color to our color chosen above
	glFogf (GL_FOG_DENSITY, density); //set the density to the value above
	glHint (GL_FOG_HINT, GL_NICEST); // set the fog to look the nicest, may slow down on older cards
	angle+=0.1;
}
else
{
	glDisable(GL_FOG);
}
	glClearColor(0.5f, 0.5f, 1.0f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	//   glTranslatef(0.5, 0.5, 0.5);
	glRotatef(spin.y, 1.0, 0.0, 0.0);
	glRotatef(spin.x, 0.0, 1.0, 0.0);

	origin->drawmodel();

	glDisable(GL_LIGHTING);
	glDisable(GL_LIGHT0);

	glutWireCube(2.0);
	drawflakes();
	drawaccumulatedsnow();

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);


	glPopMatrix();

	glutSwapBuffers();
}

void Snow::init() {
	glClearColor(0.5f, 0.5f, 1.0f, 1.0f);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

}

void Snow::reshape(int width, int height) {
	w_width = width;
	w_height = height;

//	glViewport(0, 0, width, height);
	GLUI_Master.auto_set_viewport();
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, (GLfloat) height / (GLfloat) width, 1.0, 128.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0.0, 0.0, -3.0);
	glDisable(GL_LIGHTING);
	glDisable(GL_LIGHT0);
	//  init_camera();
}

void Snow::keyboard(unsigned char key, int x, int y) {
	switch (key) {


	case 's':
		increaseSnow(1000, false);
		break;
	case 'S':
		decreasSnow(1000);
		break;

	case 'r':
		reset();
		break;

	case ' ':
		lsite->RecalculateAvalanches();
		break;

	}

	glutPostRedisplay();
}

void Snow::motion(int x, int y) {
	spin.x = lastspin.x + x - anchor.x;
	spin.y = lastspin.y + y - anchor.y;

	glutPostRedisplay();
}

void Snow::mouse(int button, int state, int x, int y) {
	switch (state) {
	case GLUT_DOWN:
		anchor.x = x;
		anchor.y = y;
		break;
	case GLUT_UP:
		lastspin = spin;
		break;
	}
	glutPostRedisplay();
}

